//
//  Track.mm
//  Racing
//
//  Created by vy phan on 4/11/11.
//  Copyright 2011 __MyCompanyName__. All rights reserved.
//

#import "Track.h"
#import "Rectangle.h"

@implementation Track
-(id)init
{
	self = [super init];
	if (self != nil) {
		self->height = -1;
		self->width = -1;
		self->version = @"1.0";
		self->sections = [[NSMutableArray alloc]init];
	}
	return self;
}

-(id)initWithVersion:(NSString *)version_
{
	self = [super init];
	if (self != nil) {
		self->height = -1;
		self->width = -1;
		self->version = version_;
		self->sections = [[NSMutableArray alloc]init];
	}
	return self;
}
-(int) getWidth
{
	if (width == -1) {
		[self calcDimensions];
	}
	return self->width;
}
-(int) getHeight
{
	if (height == -1) {
		[self calcDimensions];
	}
	return self->height;
}
-(NSString*) getVersion
{
	return self->version;
}
/* read file line by line
 */
NSString *readLineAsNSString(FILE *file)
{
    char buffer[4096];
	
    // tune this capacity to your liking -- larger buffer sizes will be faster, but
    // use more memory
    NSMutableString *result = [NSMutableString stringWithCapacity:256];
	
    // Read up to 4095 non-newline characters, then read and discard the newline
    int charsRead;
    do
    {
        if(fscanf(file, "%4095[^\n]%n%*c", buffer, &charsRead) == 1)
            [result appendFormat:@"%s", buffer];
        else
            break;
    } while(charsRead == 4095);
	
    return result;
}


-(void) load:(NSString*)track_
{
	FILE *file = nil;
	file = fopen([track_ cStringUsingEncoding:1],"r");
	// check for NULL
	if (file == nil) {
		NSLog([track_ stringByAppendingString:@" not found"]);
		return;
	}
	else {
		NSMutableArray *sectionsVector = [[NSMutableArray alloc]initWithCapacity:256];
		// check for NULL
		while(!feof(file))
		{
			NSString *line = readLineAsNSString(file);
			// do stuff with line; line is autoreleased, so you should NOT release it (unless you also retain it beforehand)
			NSArray *tokens = [line componentsSeparatedByString:@" "];
			NSString *sectionType = (NSString*)[tokens objectAtIndex:0];
			// version
			if ( [sectionType isEqualToString:@"version"] )
				self->version = (NSString*)[tokens objectAtIndex:1];
			
			// straight section
			if ( [sectionType isEqualToString:@"straight"] )
			{
				BOOL vertical = [((NSString*)[tokens objectAtIndex:1]) isEqualToString:@"vert"];
				BOOL horizontal = [((NSString*)[tokens objectAtIndex:1]) isEqualToString:@"horiz"];
				if (!vertical && !horizontal) {
					NSLog(@"Section must be vertical or horizontal");
					return;
				}
				int x = [((NSString*)[tokens objectAtIndex:2]) intValue];
				int y = [((NSString*)[tokens objectAtIndex:3]) intValue];
				StraightSection *straightSection = [[StraightSection alloc]initWithVertical:vertical X:x Y:y];
				[sectionsVector addObject:straightSection];
				[straightSection release];
			}
			// corner section
			if ( [sectionType isEqualToString:@"corner"] ) {
				NSString *param1 = (NSString*)[tokens objectAtIndex:1];
				BOOL left = [param1 isEqualToString:@"left"];
				BOOL right = [param1 isEqualToString:@"right"];
				if (!left && !right) {
					NSLog(@"Section corner must be left or right");
				}
				NSString *param2 = (NSString*)[tokens objectAtIndex:2];
				BOOL top = [param2 isEqualToString:@"top"];
				BOOL bottom = [param2 isEqualToString:@"bottom"];
				if ( !top && !bottom ) {
					NSLog(@"Section corner must be top or bottom");
				}
				int x = [((NSString*)[tokens objectAtIndex:3]) intValue];
				int y = [((NSString*)[tokens objectAtIndex:4]) intValue];
				CornerSection *cornerSection = [[CornerSection alloc] initWithLeft:left Top:top X:x Y:y];
				[sectionsVector addObject:cornerSection];
				[cornerSection release];
			}
		}
		fclose(file);
		int sectionsCount = [sectionsVector count];
		for (int i = 0; i < sectionsCount; i++) {
			[sections addObject:[sectionsVector objectAtIndex:i]];
		}
		[sectionsVector release];
		for (int i = 0; i < [sections count]; i++) {
			[((Section*)[sections objectAtIndex:i]) setNextSection:(Section*)[sections objectAtIndex:(i+1)%[sections count]]];
		}
		[self calcDimensions];
	}
}
-(void) calcDimensions
{
	width = -1;
	height = -1;
	int sectionsCount = [sections count];
	for ( int i = 0; i < sectionsCount; i++ ) {
		Rectangle *bounds = [((Section*)[sections objectAtIndex:i]) getBounds];//sections[ i ].getBounds();
		width = width > ([bounds x] + [bounds width]) ? width : ([bounds x] + [bounds width]);
		width = height > ([bounds y] + [bounds height]) ? height : ([bounds y] + [bounds height]);
		//[bounds release];
		//width  = Math.max( width, bounds.x + bounds.width );
		//height = Math.max( height, bounds.y + bounds.height );
	}
}
/** Put the vehicles on the starting grid. **/

-(void) toStartingPositions:(NSMutableArray*)vehicles_
{
	if (sections == nil || [sections count] < 2) {
		NSLog(@"A track must have at least two sections");
		return;
	}
	// mem leak
//	Section *start = [[Section alloc] init];
//	Section *end = [[Section alloc] init];
	//end
	Section *start = (Section*)[sections objectAtIndex:0];
	Section *next = (Section*)[sections objectAtIndex:1];
	//mem leak
//	Rectangle *startBounds = [[Rectangle alloc]init];
//	Rectangle *nextBounds = [[Rectangle alloc]init];
	//end
	Rectangle *startBounds = [start getBounds];
	Rectangle *nextBounds = [next getBounds];
	
	float dx = [nextBounds x] - [startBounds x];
	float dy = [nextBounds y] - [startBounds y];
	
	float dist = (float)sqrt( dx*dx + dy*dy );
	dx /= dist;
	dy /= dist;
	
	float x = [startBounds x] + 0.5f * [startBounds width];
	float y = [startBounds y] + 0.5f * [startBounds height];
	float width = startBounds.width*0.75f;
	
	float dir = (float)atan2( dx, dy );
	
	int vehiclesCount = [vehicles_ count];
	
	for ( int i = 0; i < vehiclesCount; i++ ) {
		State *state = [((Vehicle*)[vehicles_ objectAtIndex:i]) currentState];
		[state halt];
		state->angle = dir;
		float rel = (i/(float)(1 > ([vehicles_ count] -1 ) ? 1 : ([vehicles_ count] -1 ))) - 0.5f;
		state->x = x - rel * width * dy;
		state->y = y + rel * width * dx;
		[((Vehicle*)[vehicles_ objectAtIndex:i]) integrate:0.0f];
		[((Vehicle*)[vehicles_ objectAtIndex:i]) update];
	}
}

-(void)dealloc
{
	[self->sections release];
	[self->version release];
	[super dealloc];
}
@end
